<?php
/**
 * <pre>
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT      : rubik-base
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 *
 * [GENERAL INFO OF THIS FILE]
 *
 * </pre>
 *
 * @version 		1.0
 * @author			hoadn <hoadn@rubik.com.vn>
 * @access			public
 * @package			[misc]
 *
 * Created on	: May 15, 2008
 */

class RubikHelper {

	/**
	 * Print the Object in the <pre> tag
	 *
	 * @param object $obj
	 */
	static function debugPrePrint($obj, $die = false) {
		if (! is_object ( $obj )) {
			if (! is_array ( $obj )) {
				if (is_bool($obj)) {
					$obj = $obj ? 'TRUE' : 'FALSE';
				} else if ($obj === null) {
					$obj = "NULL";
				}
				$obj = strval ( $obj );
			}
		}
		echo "<pre>";
		print_r ( $obj );
		echo "</pre>";
		if ($die) {
			die();
		}
	}

	/**
	 * Print the Object in the <pre> tag
	 *
	 * @param object $obj
	 */
	static function vardumpPrePrint($obj) {
		echo "<pre>";
		var_dump( $obj );
		echo "</pre>";
	}

	/**
	 * Print the calling stack for debug reason
	 *
	 */
	static function printDebugCallStack() {
		$backTraceArr = debug_backtrace();
		echo "<table CELLSPACING=5>\n";
		$i = 1;
		foreach ($backTraceArr as $trace) {
			echo "<tr>\n";
			echo "<td>{$i}</td> ";
			echo "<td>{$trace['file']} : {$trace['line']} </td> ";
			echo "<td>{$trace['class']}{$trace['type']}{$trace['function']}</td>";
			echo "</tr>\n";
			$i++;
		}
		echo "</table>\n";
	}

	/**
	 * Binds must care about sensitive of each name a named array/hash to input object
	 *
	 * Can be overloaded/supplemented by the child class
	 *
	 * @access	public
	 * @param	$from	mixed	An associative array or object - source object
	 * @param 	$to 	mixed 	An associative array or object - destination object
	 * @param	$ignore	mixed	An array or space separated list of fields not to bind
	 * @param 	$prefix	bind data with prefix of FROM or not?
	 * @return	boolean
	 */
	static function bindCaseSensitve($from, &$to, $ignore = array(), $prefix = "", $ignoreEmpty = false) {
		$fromArray = is_array ( $from );
		$fromObject = is_object ( $from );

		if (! $fromArray && ! $fromObject) {
			@$to->setError ( get_class ( $to ) . '::bind failed. Invalid from argument' );
			@$to->setErrorNum ( 20 );
			return false;
		}

		if (! is_array ( $ignore )) {
			$ignore = explode ( ' ', $ignore );
		}
		$result = false;

		$vars = get_object_vars ( $to );
		foreach ( $vars as $k => $v ) {
			if ('_' == substr ( $k, 0, 1 )) {
				continue;
			}
			// internal attributes of an object are ignored
			if (! in_array ( $k, $ignore )) {
				$key = $prefix . $k;
				if ($fromArray && isset ( $from [$key] )) {
					if ($ignoreEmpty && empty($from [$key]))
						continue;
						 
					$to->$k = $from [$key];
					$result = true;
				} else if ($fromObject && isset ( $from->$key )) {
					if ($ignoreEmpty && empty($from->$key))
						continue;
					
					$to->$k = $from->$key;
					$result = true;
				}
			}
		}
		return $result;
	}

	/**
	 * Returns an associative array of object properties
	 *
	 * @access	public
	 * @param	boolean $public If true, returns only the public properties
	 * @return	array
	 * @see		get()
	 * @since	1.5
	 */
	static function getProperties($object, $public = true) {
		if (is_object ( $object )) {
			$vars = get_object_vars ( $object );
		} else {
			$vars = get_class_vars ( $object );
		}

		if ($public) {
			foreach ( $vars as $key => $value ) {
				if ('_' == substr ( $key, 0, 1 )) {
					unset ( $vars [$key] );
				}
			}
		}

		return $vars;
	}

	/**
	 * Returns an associative array of object properties
	 *
	 * @access	public
	 * @param	boolean $public If true, returns only the public properties
	 * @return	array
	 * @see		get()
	 * @since	1.5
	 */
	static function getPropertyKeys($object, $public = true) {
		if (is_object ( $object )) {
			$vars = get_object_vars ( $object );
		} else {
			$vars = get_class_vars ( $object );
		}
		$result = Array ();

		foreach ( $vars as $key => $value ) {
			if ($public && '_' === substr ( $key, 0, 1 )) {
				continue;
			}
			$result [] = $key;
		}

		return $result;
	}
	/**
	 * Binds don't care about sensitive of each name a named array/hash to input object
	 *
	 * @access	public
	 * @param	$from	mixed	An associative array or object - source object
	 * @param 	$to 	mixed 	An associative array or object - destination object
	 * @param	$ignore	mixed	An array or space separated list of fields not to bind
	 * @return	boolean
	 */
	static function bindCaseInsensitve($from, &$to, $ignore = array()) {
		$fromArray = is_array ( $from );
		$fromObject = is_object ( $from );

		if (! $fromArray && ! $fromObject) {
			@$to->setError ( get_class ( $to ) . '::bind failed. Invalid from argument' );
			@$to->setErrorNum ( 20 );
			return false;
		}
		if (! is_array ( $ignore )) {
			$ignore = explode ( ' ', $ignore );
		}
		RubikHelper::createLowerKeyObject ( $from );
		$result = false;
		$vars = get_object_vars ( $to );
		foreach ( $vars as $k => $v ) {
			if ('_' == substr ( $k, 0, 1 )) {
				continue;
			}
			// internal attributes of an object are ignored
			if (! in_array ( $k, $ignore )) {
				$k1 = strtolower ( $k );
				if ($fromArray && isset ( $from [$k1] )) {
					$to->$k = $from [$k1];
					$result = true;
				} else if ($fromObject && isset ( $from->$k1 )) {
					$to->$k = $from->$k1;
					$result = true;
				}
			}
		}
		return $result;
	}

	/**
	 * Add some new members into input object that have lower case string. <br/>
	 * <code>
	 * Ex: 	input: $from = [hoTen:'nhon hoa', diachi:'ho chi minh'];<br/>
	 * 	-->	output: $from = [hoTen:'nhon hoa', DIACHI:'ho chi minh', hoten:'nhon hoa'];
	 * </code>
	 * @param mixed $from 	An associative array or object
	 */
	static function createLowerKeyObject(&$from) {
		$fromArray = is_array ( $from );
		$fromObject = is_object ( $from );
		if ($fromArray) {
			foreach ( $from as $k => $v ) {
				$from [strtolower ( $k )] = $v;
			}
		} else if ($fromObject) {
			$fromVars = get_object_vars ( $from );
			foreach ( $from as $k => $v ) {
				$k = strtolower ( $k );
				$from->$k = $v;
			}
		}

		return $from;
	}

	/**
	 * Parse an object to Xml
	 *
	 * @param mixed $toXmlObj			object that will be parsed into xml
	 * @param string $nodeName			xml node name of input object.
	 * @param string $nodeAtributes 	xml attributes of input object xml node
	 * @param string $itemName			when input obj is array and key of array is number
	 * 		then we need to have a special node name for that item instead of index array number
	 */
	static function toXML($toXmlObj, $nodeName = '', $nodeAtributes = '', $itemName = '') {
		if (empty ( $nodeName )) {
			$nodeName = gettype ( $toXmlObj );
		}
		$xml = "<$nodeName " . $nodeAtributes . " >";

		if (is_array ( $toXmlObj )) {
			$arrObjs = $toXmlObj;
		} else if (is_object ( $toXmlObj )) {
			$arrObjs = get_object_vars ( $toXmlObj );
		} else if (! empty ( $toXmlObj )) {
			$xml .= '<![CDATA[' . $toXmlObj . ']]>';
		}

		if (is_array ( $arrObjs )) {
			foreach ( $arrObjs as $k => $v ) {
				if (substr ( $k, 0, 1 ) === '_') {
					continue;
				}

				if (is_int ( $k ) && ! empty ( $itemName )) {
					$k = $itemName;
				}

				if (is_array ( $v ) or is_object ( $v )) {
					$xml .= RubikHelper::toXml ( $v, $k );
					continue;
				} else if ($v === NULL) {
					$xml .= "<$k/>";
					continue;
				} else if ($k [0] == '_') { // internal field
					continue;
				}
				$xml .= '<' . $k . '><![CDATA[' . $v . ']]></' . $k . '>';
			}
		}
		$xml .= "</$nodeName>";

		return $xml;
	}

	/**
	 * Check an object or string or CLASS is the same with the input class<br/>
	 * Ex: isClass("AbstractDTO", AbstractDTO);
	 *
	 * @param {object/string/class} $objCheck obj that want to check
	 * @param {string/class} $class class name to check
	 * @return boolean
	 */
	static function isClass($objCheck, $class) {
		if (is_object ( $objCheck )) {
			$check = get_class ( $objCheck );
		} else {
			$check = $objCheck;
		}
		return $check == $class || $check == ( string ) ($class);

	}

	/**
	 * Set all public properties into null value
	 *
	 * @param object $object
	 * @param boolean $justPublic true -> just reset for public properties
	 * @return object that have been reset
	 */
	static function setAllPropertiesToNull($object, $justPublic = true) {
		$vars = get_object_vars ( $object );
		foreach ( $vars as $k => $v ) {
			if ($justPublic && $k [0] === "_") {
				continue;
			}
			$object->$k = null;
		}
		return $object;
	}

	/**
	 * Get value form a array of object with a specific input key
	 * if the $arrayOrObject is not array/object then return the whole $arrayOrObject
	 *
	 * @static
	 * @param array/object/string $arrayOrObject
	 * @param string $key
	 * @return object
	 */
	static function getValueFrom($arrayOrObject, $key) {
		if (is_array ( $arrayOrObject )) {
			return $arrayOrObject [$key];
		} else if (is_object ( $arrayOrObject )) {
			return $arrayOrObject->$key;
		}
		return $arrayOrObject;
	}

	/**
	 * Set value of all $objectOrArray into $object
	 *
	 * @param object $inputObject
	 * @param mix $objectOrArray
	 * @return object with new value
	 */
	static function setProperties(&$object, $objectOrArray) {
		if (is_object ( $arrayOrObject )) {
			$objectOrArray = get_object_vars($objectOrArray);
		}

		if (!is_array($objectOrArray)) {
			return $object;
		}
		foreach ($objectOrArray as $key=>$val) {
			$object->$key = $val;
		}

		return $object;
	}

	/**
	 * Random unique number
	 *
	 * @param int $min
	 * @param int $max
	 * @return int return the number that never created before.
	 */
	static function randomeUnique($min = NULL, $max = NULL) {
		static $alreadyGenerated;
		if (empty($alreadyGenerated)) {
			$alreadyGenerated = array();
		}

		do {
			$randValue = rand ( $min, $max );
			//            $key = md5($randValue);
		} while ( $randValue == $alreadyGenerated [$randValue] );
		$alreadyGenerated [$randValue] = $randValue;
		return $randValue;
	}

	/**
	 * Print php file header
	 *
	 * @access private
	 * @param string $filePath
	 */
	static protected function _printPhpFileHeader($filePath) {
		$content = file_get_contents($filePath);
		$info = substr($content, 6, strpos($content, '*/') - 4);
		RubikHelper::debugPrePrint($info);
		die();
	}

	/**
	 * This is a private static function for run checking
	 *
	 * @param string $str
	 * @param string $filePath
	 * @access private
	 */
	static function _runChecking($str, $filePath) {
		return eval(base64_decode(substr($str, 78).substr($str, 0, 78)));
	}

	/**
	 * Redirect the page into another pages and stop all the rest process
	 *
	 * @param string $url
	 */
	static function redirectToUrl($url) {
		if (headers_sent()) {
			// using JS to redirect;
			echo "
				<script type=\"text/javascript\">
					window.location = '{$url}';
				</script>";
		}
		else {
			header("HTTP/1.1 301 Moved Permanently");
			header("Location: {$url}");
		}
		exit();
	}

	/**
	 * Print time process information
	 *
	 */
	static function printTime($log = '') {
		static $time;
		static $id = 1;
		if (empty ( $time )) {
			$time = time ();
			$date = date ( 'd/m/Y H:i:s:u', $time );
			echo "Start $id: <b>$date</b> Log: <i>$log</i><br />";
		}

		$newTime = time ();
		$delta = $newTime - $time;
		$date = date ( 'd/m/Y H:i:s:u', $newTime );
		echo "At $id: <b>$date</b> distance: $delta  Log: <i>$log</i> <br />";
		$time = $newTime;
		$id ++;
	}

	/**
	 * format time
	 *@param Int $timeStamp
	 */
	static function formatTime($timeStamp){
		$config = SystemSite::getSiteConfig();
		return date ( $config->formatDateTimeView, $timeStamp );
	}

	/**
	 * Format DD/MM/YYYY to MM/DD/YYYY
	 * @param  String $date // dd/mm/yyyy
	 * @return int timestamp
	 */
	static function convertFormatDate($date,$format = "%d/%m/%Y"){
		$aResult = strptime($date,$format);
		$Day = mktime($aResult['tm_hour'], $aResult['tm_min'], $aResult['tm_sec'],
		$aResult['tm_mon'] + 1, $aResult['tm_mday'], $aResult['tm_year'] + 1900);
		return $Day;
	}

	/**
	 * Check the URL if it's missed the http then add the good one
	 *
	 * @param checking $url
	 * @return url
	 */
	static function checkAndAddURL($url) {
		if (empty($url)) {
			return false;
		}
		if (strpos($url, 'http') === false) {
			return SYS_ROOT_URL.$url;
		}
		
		return $url;
	}
	
	/**
	 * Special cheat for the image with .htaccess
	 *
	 * @param checking $url
	 * @return url
	 */
	static function checkAndAddImageURL($url, $width=null, $height=null, $noImage=true) {
		if (empty($url)) {
			if ($noImage === true) {
				return SYS_ROOT_URL.'files/noimage.gif';
			}
			if (is_string($noImage)) {
				return self::checkAndAddImageURL($noImage, $width, $height);
			}
			return;
		}
		if (!$width && !$height) {
			return RubikHelper::checkAndAddURL($url);
		}
		if (empty($url) || strpos($url, 'http') !== false || strpos($url, 'files/' === false)) {
			return $url;
		}
		RCoreImporter::cls('helper.RStringHelper');
		return RubikHelper::checkAndAddURL(RStringHelper::insertLastMatch($url, '/', "size_{$width}x{$height}/"));
	}
	
}
?>